using System;
using ch.ethz.ssh2.log;
using System.Threading;
namespace ch.ethz.ssh2.channel
{

    /// <summary> RemoteAcceptThread.
    /// 
    /// </summary>
    /// <author>  Christian Plattner
    /// </author>
    /// <version>  2.50, 03/15/10
    /// </version>
    public class RemoteAcceptThread
    {
        //UPGRADE_NOTE: Final was removed from the declaration of 'log '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
        //UPGRADE_NOTE: The initialization of  'log' was moved to static method 'ch.ethz.ssh2.channel.RemoteAcceptThread'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1005'"
        private static readonly Logger log;

        internal Channel channel;

        internal System.String remoteConnectedAddress;
        internal int remoteConnectedPort;
        internal System.String remoteOriginatorAddress;
        internal int remoteOriginatorPort;
        internal System.String targetAddress;
        internal int targetPort;

        internal System.Net.Sockets.TcpClient client;

        public RemoteAcceptThread(Channel channel, System.String remoteConnectedAddress, int remoteConnectedPort, System.String remoteOriginatorAddress, int remoteOriginatorPort, System.String targetAddress, int targetPort)
        {
            this.channel = channel;
            this.remoteConnectedAddress = remoteConnectedAddress;
            this.remoteConnectedPort = remoteConnectedPort;
            this.remoteOriginatorAddress = remoteOriginatorAddress;
            this.remoteOriginatorPort = remoteOriginatorPort;
            this.targetAddress = targetAddress;
            this.targetPort = targetPort;

            if (log.Enabled)
                log.log(20, "RemoteAcceptThread: " + remoteConnectedAddress + "/" + remoteConnectedPort + ", R: " + remoteOriginatorAddress + "/" + remoteOriginatorPort);
        }

        public void Run()
        {
            try
            {
                channel.cm.sendOpenConfirmation(channel);

                client = new System.Net.Sockets.TcpClient(targetAddress, targetPort);

                Thread r2l = new Thread(new ThreadStart(new StreamForwarder(channel, null, null, channel.StdoutStream, client.GetStream(), "RemoteToLocal").Run));
                StreamForwarder l2r = new StreamForwarder(channel, null, null, client.GetStream(), channel.StdinStream, "LocalToRemote");

                /* No need to start two threads, one can be executed in the current thread */

                r2l.IsBackground = true;
                r2l.Start();
                l2r.Run();

                while (r2l.IsAlive)
                {
                    try
                    {
                        r2l.Join();
                    }
                    catch (System.Threading.ThreadInterruptedException e)
                    {
                        Thread.CurrentThread.Interrupt();
                    }
                }

                /* If the channel is already closed, then this is a no-op */

                channel.cm.closeChannel(channel, "EOF on both streams reached.", true);
                client.Close();
            }
            catch (System.IO.IOException e)
            {
                //UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Throwable.getMessage' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'"
                log.log(50, "IOException in proxy code: " + e.Message);

                try
                {
                    //UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Throwable.getMessage' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'"
                    channel.cm.closeChannel(channel, "IOException in proxy code (" + e.Message + ")", true);
                }
                catch (System.IO.IOException e1)
                {
                }
                try
                {
                    if (client != null)
                        client.Close();
                }
                catch (System.IO.IOException e1)
                {
                }
            }
        }

        static RemoteAcceptThread()
        {
            log = Logger.getLogger(typeof(RemoteAcceptThread));
        }
    }
}